import base64
import hashlib
import json
import os
import random
from functools import wraps

import requests
from django.http import JsonResponse
from django_redis import get_redis_connection

from common import errors
from travel import config, settings
from user.models import User
from worker import celery_app


@celery_app.task
def sendsms(phone):
    url = config.YZX_URL

    code = getcode(4)

    json_data = {
        "sid": config.YZX_SID,
        "token": config.YZX_TOKEN,
        "appid": config.YZX_APPID,
        "templateid": config.YZX_TEMPLATE_ID,
        "param": f"{code}, 180",
        "mobile": phone,
    }

    res = requests.post(url, json=json_data)
    res = res.json()

    if res.get('code') == '000000':

        # 1,实例化redis
        redis_cli = get_redis_connection()

        # 2，保存验证码
        redis_cli.set(f'sms_code_{phone}', code, 180)

        return JsonResponse({'code': 0, 'msg': '短信发送成功'})
    else:
        return JsonResponse({'code': errors.SMS_SEND_FAIL, 'msg': '短信发送失败'})


def getcode(num):
    start = 10 ** (num - 1)
    end = 10 ** num - 1

    return random.randint(start, end)


# 生成token
def create_token(uid):
    # 1，第一部分是头部信息，包含 声明类型 和加密算法
    p1 = {
        'typ': 'JWT',
        'alg': 'HS256'
    }

    p1_base64 = base64.b64encode(json.dumps(p1).encode()).decode()

    # 2,包含用户信息
    p2 = {
        'uid': uid
    }

    p2_base64 = base64.b64encode(json.dumps(p2).encode()).decode()

    # 3, sha256(p1_base64 + p2_base64 + secret_key)
    p3 = sha256_encode(p1_base64, p2_base64)

    token = f"{p1_base64}.{p2_base64}.{p3}"

    return token


# sha256加密
def sha256_encode(p1, p2):
    data = p1 + p2 + settings.SECRET_KEY
    sha256 = hashlib.sha256()
    sha256.update(data.encode())
    p3 = sha256.hexdigest()
    return p3


# 验证token
def check_token(token):

    data = token.split('.')
    if len(data) != 3:
        return False, 0

    sign = sha256_encode(data[0], data[1])

    # 把第二部分，base64解码。获取到用户的id
    p2_base64_decode = json.loads(base64.b64decode(data[1].encode()).decode())
    uid = p2_base64_decode.get('uid')

    if sign != data[2]:
        return False, uid
    else:
        return True, uid


# 定义一个token验证装饰器
def login_decorate(func):
    @wraps(func)
    def inner(self, request, *args, **kwargs):
        # 获取token
        token = request.META.get('HTTP_AUTHORIZATION')

        # 验证token是否正确
        flag, uid = check_token(token)

        if not flag:
            # 验证不成功
            return JsonResponse({'code': errors.TOKEN_WRONG, 'msg': '验证用户登录失败'})
        request.user = User.objects.get(uid=uid)
        return func(self, request, *args, **kwargs)
    return inner


def check_code(code, phone):

    # 判断验证码是否过期
    redis_cli = get_redis_connection()
    redis_code = redis_cli.get(f'sms_code_{phone}')
    if not redis_code:
        return JsonResponse({'code': errors.CODE_EXPIRY, 'msg': '验证码已过期'})

    # 判断验证码是否正确
    if code != redis_code.decode():
        return JsonResponse({'code': errors.CODE_WRONG, 'msg': '验证码不正确'})